package cn.cutie.clot.gateway.plugin;

import cn.cutie.clotrpc.core.api.LoadBalancer;
import cn.cutie.clotrpc.core.api.RegistryCenter;
import cn.cutie.clotrpc.core.cluster.RoundRobinLoadBalancer;
import cn.cutie.clotrpc.core.meta.InstanceMeta;
import cn.cutie.clotrpc.core.meta.ServiceMeta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @Description:
 * @Author: Cutie
 * @CreateDate: 2024/6/5 00:48
 * @Version: 0.0.1
 */
@Component("clotRpcPlugin")
public class ClotRpcPlugin extends AbstractGatewayPlugin {

    public static final String NAME = "clot-rpc";
    private String prefix = GATEWAY_PREFIX +"/"+ NAME + "/";

    @Autowired
    RegistryCenter rc;

    LoadBalancer<InstanceMeta> loadBalancer = new RoundRobinLoadBalancer<>();

    // ServerWebExchange 相当于一个 context
    @Override
    public Mono<Void> doHandle(ServerWebExchange exchange, GatewayPluginChain chain) {
        System.out.println("===>>> [ClotRpcPlugin] ...");
//        byte[] bytes = "hello-100".getBytes();
//        return exchange.getResponse()
//                .writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes))
//                .doOnNext(data -> exchange.getResponse().getHeaders().setContentLength(data.readableByteCount())));

        // 1. 通过请求路径或者服务名
        System.out.println(exchange.getRequest().getPath().value());
        String service = exchange.getRequest().getPath().value().substring(prefix.length());
        ServiceMeta serviceMeta = ServiceMeta.builder().name(service)
                .app("app1").env("dev").namespace("public").build();
        // 2. 通过rc拿到所有活着的服务实例
        List<InstanceMeta> instanceMetas = rc.fetchAll(serviceMeta);
        // 3. 先简化处理，或者第一个实例url

        InstanceMeta instanceMeta = loadBalancer.choose(instanceMetas);
        System.out.println(" 2.inst size=" + instanceMetas.size() +  ", inst  " + instanceMeta);
        String url = instanceMeta.toUrl();

        // 4. 拿到请求的报文
        Flux<DataBuffer> requestBody = exchange.getRequest().getBody();

        WebClient client = WebClient.create(url);
        Mono<ResponseEntity<String>> entity = client.post()
                .header("Content-Type", "application/json")
                .body(requestBody, DataBuffer.class).retrieve().toEntity(String.class);
        // 6. 通过entity获取响应报文
        Mono<String> body = entity.map(ResponseEntity::getBody);
//        body.subscribe(souce -> System.out.println("response:" + souce)); // 这个不能乱用，订阅了消费了就没了
        // 7. 组装响应报文
        HttpHeaders headers = exchange.getResponse().getHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("clot.gw.version", "v1.0.0");
        headers.add("clot.gw.plugin", getName());

        return body.flatMap(x -> exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(x.getBytes()))))
                .then(chain.handle(exchange));
    }

    @Override
    public boolean doSupport(ServerWebExchange exchange) {
        return exchange.getRequest().getPath().value().startsWith(prefix);
    }

    @Override
    public String getName() {
        return NAME;
    }
}
